package org.jeecg.cmbCloudDirectLink.utils;

import com.google.gson.GsonBuilder;
import com.google.gson.JsonObject;
import lombok.extern.slf4j.Slf4j;
import org.jeecg.cmbCloudDirectLink.constant.CMBConstant;
import org.jeecg.common.api.dto.BankSetDTO;
import org.jeecg.common.api.vo.Result;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.HashMap;

/**
 * 国密免前置请求
 */
@Slf4j
public class SMRequest {

    /**
     * 请求发送
     * @param jObject
     * @throws Exception
     */
    public static Result<?> doProcess(JsonObject jObject, String funCode, BankSetDTO bankSetDTO) throws Exception {
        JsonObject object = new JsonObject();
        // 签名
        object.addProperty("sigdat", "__signature_sigdat__");
        object.addProperty("sigtim", DCHelper.getTime());
        jObject.add("signature", object);
        String source = DCHelper.serialJsonOrdered(jObject);
//        System.out.println("签名原文: " + source);
        byte[] signature1 = DCCryptor.CMBSM2SignWithSM3(getID_IV(bankSetDTO.getZsyhUid()), Base64.getDecoder().decode(bankSetDTO.getZsyhUserSm2PriKey()), source.getBytes(StandardCharsets.UTF_8));
        String sigdat1 = new String(Base64.getEncoder().encode(signature1));
//        System.out.println("签名结果: " + sigdat1);
        object.addProperty("sigdat", sigdat1);

        // SM4-CBC加密
        String plaintxt = jObject.toString();
//        System.out.println("加密前req:  " + plaintxt);
        byte[] enInput = DCCryptor.CMBSM4EncryptWithCBC(bankSetDTO.getZsyhUserSm4Key().getBytes(), getID_IV(bankSetDTO.getZsyhUid()), plaintxt.getBytes(StandardCharsets.UTF_8));

        String req = new String(Base64.getEncoder().encode(enInput));
//        System.out.println("加密后req:  " + req);

        // 发送请求
        HashMap<String, String> map = new HashMap<>();
        map.put("UID", bankSetDTO.getZsyhUid());
        map.put("ALG", CMBConstant.ALG_SM);
        map.put("DATA", URLEncoder.encode(req, "utf-8"));
        map.put("FUNCODE", funCode);
        String res = DCHelper.doPostForm(CMBConstant.HOST, map);
//        log.info("res:  " + res);
        try {
            Base64.getDecoder().decode(res);
        } catch (Exception e) {
            return Result.error(res);
        }

        // 解密请求
        String resplain = new String(DCCryptor.CMBSM4DecryptWithCBC(bankSetDTO.getZsyhUserSm4Key().getBytes(), getID_IV(bankSetDTO.getZsyhUid()), Base64.getDecoder().decode(res)), StandardCharsets.UTF_8);
//        log.info("res decrypt: " + resplain);

        // 验签
        JsonObject object2 = new GsonBuilder().create().fromJson(resplain, JsonObject.class);
        JsonObject object3 = object2.getAsJsonObject("signature");
        String resSign = object3.get("sigdat").getAsString();
        object3.addProperty("sigdat", "__signature_sigdat__");
        object2.add("signature", object3);
        String resSignSource = DCHelper.serialJsonOrdered(object2);
//        System.out.println("验签原文: " + resSignSource);
//        System.out.println("验签签名值: " + resSign);
        boolean verify = DCCryptor.CMBSM2VerifyWithSM3(getID_IV(bankSetDTO.getZsyhUid()), Base64.getDecoder().decode(bankSetDTO.getZsyhBankSm2PubKey()), resSignSource.getBytes(StandardCharsets.UTF_8), Base64.getDecoder().decode(resSign));
//        System.out.println("验签结果: " + verify);
        if(verify){
            return Result.ok("验签成功！",resplain);
        } else {
            return Result.error("验签失败!",resplain);
        }
    }

    /**
     * 用户编号UID，必须满足16位，不足的后面用0补齐
     * @return
     */
    private static byte[] getID_IV(String uid) {
        String userId = uid + "0000000000000000";
        return userId.substring(0, 16).getBytes();
    }

}
